/**
 * @class SafeQueue
 * @brief A thread-safe, dynamic-size, queue implementation for concurrent access and processing.
 *
 * This class provides a thread-safe queue implementation with the following features:
 * - Dynamic-size queue that can grow and shrink as needed.
 * - Enqueue and enqueue_move methods for adding elements to the queue.
 * - Thread-safe dequeue and try_dequeue methods for removing elements from the queue.
 * - Utility methods for checking queue size and emptiness.
 * - Thread-safe clear method to reset the queue state.
 *
 * @tparam T The type of elements stored in the queue.
 */ 
#pragma once
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <algorithm>

using namespace std;
class MyAVPacketList;
template<typename T>
class SafeQueue {
public:
    SafeQueue(size_t capacity = 0, bool allow_duplicates = true)
        : m_capacity(capacity),abort_request(false) {
    }
    SafeQueue(const SafeQueue<T>& other) {
        std::lock_guard<std::mutex> lock(other.m_mutex);
        if constexpr (std::is_same_v<T, std::shared_ptr<MyAVPacketList>>) {
            // 如果 T 是 std::shared_ptr<U> 类型，那么进行深拷贝
            for (const auto& item : other.m_queue) {
                m_queue.push_back(std::make_shared<MyAVPacketList>(*item));
            }
        } else {
            // 如果 T 是其他类型，那么进行浅拷贝
            m_queue = other.m_queue;
        }
        m_capacity = other.m_capacity;
        // 如果有其他成员变量，也需要在这里进行拷贝
    }


    SafeQueue(SafeQueue<T>&& other) noexcept {
        std::lock_guard<std::mutex> lock(other.m_mutex);
        m_queue = std::move(other.m_queue);  // 移动 std::queue
        m_capacity = other.m_capacity;
    }
    /**
     * 将元素压入队列。如果队列已满或者不允许重复元素且元素已存在，则返回 false。
     *
     * @tparam U 元素类型，可以是左值引用或右值引用。
     * @param[in] t 要压入队列的元素。
     * @return 如果成功将元素压入队列，则返回 true，否则返回 false。
     */
    template<typename U>
    bool push(U&& t) {
        std::unique_lock<mutex> lock(m_mutex);
        bool result = _push_internal(std::forward<U>(t));
        lock.unlock(); // 释放锁
        if (result) {
            m_cv_pop.notify_one();// 通知其他线程可以继续出队
        }
        return result;
    }
    bool push(T& t) {
        std::unique_lock<mutex> lock(m_mutex);
        bool result = _push_internal(t);
        lock.unlock(); // 释放锁
        if (result) {
            m_cv_pop.notify_one();// 通知其他线程可以继续出队
        }
        return result;
    }

    template<typename... Args>
    bool emplace(Args&&... args) {
        std::unique_lock<std::mutex> lock(m_mutex);
        T t(std::forward<Args>(args)...);
        bool result = _push_internal(std::move(t));
        lock.unlock(); // 释放锁
        if (result) {
            m_cv_pop.notify_one();
        }
        return result;
    }

    /**
     * 尝试将元素压入队列，可能会根据超时时间进行等待。
     *
     * @tparam Rep 表示时间的数量类型，默认为 int64_t。
     * @tparam Period 时间单位类型，默认为 std::ratio<1>，即秒。
     * @tparam Duration std::chrono::duration 类型，默认为 std::chrono::duration<Rep, Period>。
     * @param[in] t 要压入队列的元素。
     * @param[in] timeout 等待队列非满的超时时间。
     *                  默认值为 Duration::zero()，表示不等待，如果不能插入就直接返回。
     *                  当传入 Duration::max() 时，表示无限等待插入。
     *                  当传入大于零的时间时，表示等待最多等待超时时间再插入。
     * @return 如果成功将元素压入队列，则返回 true，否则返回 false。
     */
    template<typename Rep = int64_t, typename Period = std::ratio<1>, typename Duration = std::chrono::duration<Rep, Period>>
    bool try_push(T&& t, const Duration& timeout = Duration::zero()) {
        std::unique_lock<mutex> lock(m_mutex);

        if (timeout == Duration::zero()) {
            if (!_push_internal(std::forward<T>(t))) {
                return false;
            }
        } else if (timeout == Duration::max()) {
            m_cv_push.wait(lock, [this]() { return abort_request || m_queue.size() < m_capacity; });
            if (!_push_internal(std::forward<T>(t))) {
                return false;
            }
        } else {
            if (!m_cv_push.wait_for(lock, timeout, [this]() { return abort_request || m_queue.size() < m_capacity; })) {
                return false;
            }
            if (!_push_internal(std::forward<T>(t))) {
                return false;
            }
        }

        lock.unlock(); // 释放锁
        m_cv_pop.notify_one();
        return true;
    }
    bool pop(T& t) {
        std::unique_lock<std::mutex> lock(m_mutex);
        bool result = _pop_internal(t);
        lock.unlock(); // 释放锁
        m_cv_push.notify_one(); // 通知其他线程可以继续入队
        return result;
    }



    /**
     * 尝试等待并弹出队列中的元素。
     * 如果在给定的超时时间内队列为空，则返回 false，否则返回 true 并将弹出的元素存储在 t 中。
     *
     * @tparam Rep 表示时间的数量类型，默认为 int64_t。
     * @tparam Period 时间单位类型，默认为 std::ratio<1>，即秒。
     * @tparam Duration std::chrono::duration 类型，默认为 std::chrono::duration<Rep, std::micro>，即微秒。
     * @param[out] t 用于存储弹出的元素。
     * @param[in] timeout 等待队列非空的超时时间。
     *                  默认值为 Duration::max()，表示无限等待。
     *                  当传入 Duration::zero() 时，表示不等待，如果队列为空则直接返回 false。
     *                  当传入大于零的时间时，表示等待指定的超时时间。
     * @return 如果在超时时间内成功弹出元素，则返回 true，否则返回 false。
     */
    template<typename Rep = int64_t, typename Period = std::ratio<1>, typename Duration = std::chrono::duration<Rep, std::micro>>
    bool try_wait_and_pop(T &t, const Duration& timeout = Duration::max()) {
        std::unique_lock<mutex> lock(m_mutex);

        if (timeout == Duration::zero()) {
            if (!_pop_internal(t)) {
                return false;
            }
        } else if (timeout == Duration::max()) {
            m_cv_pop.wait(lock, [this]() {return abort_request ||  !m_queue.empty(); });
            if (!_pop_internal(t)) {
                return false;
            }
        } else {
            if (!m_cv_pop.wait_for(lock, timeout, [this]() { return abort_request || !m_queue.empty(); })) {
                return false;
            }
            if (!_pop_internal(t)) {
                return false;
            }
        }

        lock.unlock(); // 释放锁
        m_cv_push.notify_one(); // 通知其他线程可以继续入队
        return true;
    }
// 检查队列是否为空
    bool empty() const {
        unique_lock<mutex> lock(m_mutex);
        return m_queue.empty();
    }
// 获取队列大小
    size_t size() const {
        unique_lock<mutex> lock(m_mutex);
        return m_queue.size();
    }
    void set_abort_request(bool value) {
        std::unique_lock<std::mutex> lock(m_mutex);
        abort_request = value;
       if(abort_request == true){
           m_cv_pop.notify_all();
           m_cv_push.notify_all();
       }
    }

    size_t get_total_size() {
        std::unique_lock<std::mutex> lock(m_mutex);
        return size()*sizeof(T);
    }


// 清空队列 
    void clear() {
      std::lock_guard<std::mutex> lock(m_mutex);
      while (!m_queue.empty()) {
          m_queue.pop_front();
      }
      m_cv_push.notify_all();
  }
// 设置队列容量
  void set_capacity(size_t capacity) {
      std::unique_lock<std::mutex> lock(m_mutex);
      m_capacity = capacity;
      while (m_queue.size() > m_capacity) {
          m_queue.pop_front();
      }
      m_cv_push.notify_all();
  }


private:
    deque <T> m_queue;
    size_t m_capacity = 0; // 允许的队列大小
    condition_variable m_cv_pop; 
    condition_variable m_cv_push;
    mutable std::mutex m_mutex;
    bool abort_request;

    template<typename U>
    bool _push_internal(U&& t) {
        // 如果队列容量大于 0 且队列大小已达到容量上限，则返回 false
        if (m_capacity > 0 && m_queue.size() >= m_capacity) {
            return false;
        }

        // 将元素压入队列（右值引用使用 std::forward 转发）
        m_queue.push_back(std::forward<U>(t));
        return true;
    }


    bool _push_internal(const T& t) {
        // 如果队列容量大于 0 且队列大小已达到容量上限，则返回 false
        if (m_capacity > 0 && m_queue.size() >= m_capacity) {
            return false;
        }
        // 将元素压入队列（右值引用使用 std::forward 转发）
        m_queue.push_back(t);
        return true;
    }    
    // 私有函数：尝试从队列中弹出元素，成功时返回 true，失败时返回 false。
    bool _pop_internal(T &t) {
        if (m_queue.empty()) {
            return false;
        }
        t = std::move(m_queue.front());
        m_queue.pop_front();
        return true;
    }

};
